﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Drawing;
using ClsJcPimDll = JcMBP.ClsJcPimDll;

namespace PIM_ATE
{
    sealed class JcPIMForMultiBand : JcPIMRunner
    {
        const string lf = "";
        bool m_isInited;
        string m_address;
        JcPIMDataSettings m_pim_settings;
        List<JcPIMDataResults> m_pim_resultLists = new List<JcPIMDataResults>();
        ImpCtrl m_ctrl;
        delegate bool DelStartTest();

        public JcPIMForMultiBand(string address)
        {
            m_isInited = false;
            m_address = address;
            m_ctrl = new ImpCtrl();
        }

        public override void start_settings(JcPIMDataSettings settings)
        {
            m_pim_settings = settings;
            m_pim_resultLists.Clear();
        }

        public override void start_test()
        {
            start_test_async();
        }

        public override void stop_test()
        {
            Monitor.Enter(m_ctrl);
            m_ctrl.bQuit = true;
            Monitor.Exit(m_ctrl);
        }

        void start_test_async()
        {
            DelStartTest del_start_test = new DelStartTest(start_test_sync);
            del_start_test.BeginInvoke(evt_complete_test_async, del_start_test);
        }

        bool start_test_sync()
        {
            bool complete = false;
            if (init(m_address))
            {
                if (m_pim_settings.Mode == ImMode.Freq)
                    complete = freq_sweep();
                else
                    complete = time_sweep();
            }
            return complete;
        }

        void evt_show_msg(string msg, MSG_TYPE type)
        {
            On_evt_show_log_handle(msg, null);

            if (type == MSG_TYPE.ERROR_NET || type == MSG_TYPE.ERROR_SET || type == MSG_TYPE.ERROR_TEST)
            {
                On_evt_show_error_handle(msg, null);
            }
        }

        void evt_update_ui(object obj, EventArgs e)
        {
            On_evt_get_point_handle(obj, e);
        }

        void evt_complete_test_async(IAsyncResult result)
        {
            bool complete = (result.AsyncState as DelStartTest).EndInvoke(result);

            if (m_isInited) ClsJcPimDll.fnSetExit();
            m_isInited = false;
            evt_show_msg("connect: closen" + lf, MSG_TYPE.LOG_NET);
            if (complete)
                On_evt_complete_test_handle(m_pim_resultLists, null);
            else
                On_evt_complete_test_handle(null, null);
        }

        bool init(string address)
        {
            int s = -10000;

            try
            {
                s = ClsJcPimDll.fnSetInit(address);
            }
            catch (Exception ex)
            {
                m_isInited = false;
                evt_show_msg(ex.Message + lf, MSG_TYPE.ERROR_NET);
                return false;
            }

            if (s == 0)
            {
                evt_show_msg("connect: success" + lf, MSG_TYPE.LOG_NET);
                m_isInited = true;
            }
            else
            {
                byte[] bError = new byte[512];
                ClsJcPimDll.JcGetError(bError, 512);
                m_isInited = false;
                evt_show_msg("connect-Error: \r\n" + Encoding.UTF8.GetString(bError) + lf, MSG_TYPE.ERROR_NET);
            }

            return m_isInited;
        }

        string version()
        {
            int a = 0, b = 0, c = 0, d = 0;
            ClsJcPimDll.JcGetDllVersion(ref a, ref b, ref c, ref d);
            return a.ToString() + "," + b.ToString() + "," + c.ToString() + "," + d.ToString();
        }

        bool ROSC()
        {
            if (ClsJcPimDll.fnCheckTwoSignalROSC() <= -10000)
            {
                return false;
            }
            return true;
        }

        bool freq_sweep()
        {
            Monitor.Enter(m_ctrl);
            m_ctrl.bQuit = false;
            Monitor.Exit(m_ctrl);
            int s;
            double freq_mhz = 0;
            double val = 0;
            double p1 = 0, p2 = 0;

            s = ClsJcPimDll.HwSetMeasBand(m_pim_settings.Band_TX1,
                              m_pim_settings.Band_TX2,
                              m_pim_settings.Band_RX);
            s = ClsJcPimDll.HwSetDutPort(m_pim_settings.Port_TX1,
                                         m_pim_settings.Port_TX2,
                                         m_pim_settings.Port_RX);
            if (s <= -10000)
            {
                evt_show_msg("exec-Error: set switch error(" + s.ToString() + ")" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }
            ClsJcPimDll.fnSetImOrder((byte)m_pim_settings.Order);
            ClsJcPimDll.fnSetTxPower(m_pim_settings.TX1,
                         m_pim_settings.TX2,
                         m_pim_settings.Offset1,
                         m_pim_settings.Offset2);
            s = ClsJcPimDll.fnSetTxFreqs(m_pim_settings.F1s,
                             m_pim_settings.F2e,
                             "mhz");
            if (s == -10018)
            {
                evt_show_msg("exec-Error: No find power" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }
            else if (s <= -10000)
            {
                evt_show_msg("exec-Error: Tx out of range(" + s.ToString() + ")" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }

            try
            {
                p1 = ClsJcPimDll.HwGetDsp(ClsJcPimDll.JC_CARRIER_TX1);
                p2 = ClsJcPimDll.HwGetDsp(ClsJcPimDll.JC_CARRIER_TX2);
            }
            catch
            {
                p1 = m_pim_settings.TX1;
                p2 = m_pim_settings.TX2;
            }

            ClsJcPimDll.fnSetTxOn(true, ClsJcPimDll.JC_CARRIER_TX1TX2);

            List<XPlot> lstPoint = new List<XPlot>();
            double n1 = 0, n2 = 0, f = 0;
            if (m_pim_settings.StepRx == 0)
            {
                if (m_pim_settings.Step1 <= 0) m_pim_settings.Step1 = 1;
                n1 = Math.Ceiling((m_pim_settings.F1e - m_pim_settings.F1s) / m_pim_settings.Step1) + 1;
                if (m_pim_settings.Step2 <= 0) m_pim_settings.Step2 = 1;
                n2 = Math.Ceiling((m_pim_settings.F2e - m_pim_settings.F2s) / m_pim_settings.Step2) + 1;

                f = m_pim_settings.F1s;
                for (int i = 0; i < n1; ++i)
                {
                    if (f > m_pim_settings.F1e) f = m_pim_settings.F1e;
                    lstPoint.Add(new XPlot(f, m_pim_settings.F2e, 0));
                    f += m_pim_settings.Step1;
                }

                f = m_pim_settings.F2e;
                for (int i = 0; i < n2; ++i)
                {
                    if (f < m_pim_settings.F2s) f = m_pim_settings.F2s;
                    lstPoint.Add(new XPlot(m_pim_settings.F1s, f, 0));
                    f -= m_pim_settings.Step2;
                }
            }
            else
            {
                double n = Math.Ceiling((m_pim_settings.RXe - m_pim_settings.RXs) / m_pim_settings.StepRx) + 1;
                f = m_pim_settings.RXs;
                for (int i = 0; i < n; ++i)
                {
                    if (f > m_pim_settings.RXe) f = m_pim_settings.RXe;
                    double f1 = sumF1FromPIMFreq(m_pim_settings.F2Set, f, (int)m_pim_settings.Order, m_pim_settings.isHigh);
                    f += m_pim_settings.StepRx;

                    if (f1 < m_pim_settings.F1Set || f1 > m_pim_settings.F2Set) continue;
                    lstPoint.Add(new XPlot(f1, m_pim_settings.F2Set, 0));
                    n1++;
                }

                f = m_pim_settings.RXs;
                for (int i = 0; i < n; ++i)
                {
                    if (f > m_pim_settings.RXe) f = m_pim_settings.RXe;
                    double f2 = sumF2FromPIMFreq(m_pim_settings.F1Set, f, (int)m_pim_settings.Order, m_pim_settings.isHigh);
                    f += m_pim_settings.StepRx;

                    if (f2 < m_pim_settings.F1Set || f2 > m_pim_settings.F2Set) continue;
                    lstPoint.Add(new XPlot(m_pim_settings.F1Set, f2, 0));
                    n2++;
                }
            }

            for (int i = 0; i < lstPoint.Count; ++i)
            {
                Monitor.Enter(m_ctrl);
                bool isQuit = m_ctrl.bQuit;
                Monitor.Exit(m_ctrl);
                if (isQuit)
                {
                    ClsJcPimDll.fnSetTxOn(false, ClsJcPimDll.JC_CARRIER_TX1TX2);
                    evt_show_msg("exec: test stop" + lf, MSG_TYPE.LOG_TEST);
                    return true;
                }

                if (i != 0)
                {
                    int iRes = ClsJcPimDll.fnSetTxFreqs(lstPoint[i].X1, lstPoint[i].X2, "mhz");
                    if (iRes <= -10000)
                    {
                        ClsJcPimDll.fnSetTxOn(false, ClsJcPimDll.JC_CARRIER_TX1TX2);
                        evt_show_msg("exec-Error: SetTxFreqs" + lf + "F1:" + lstPoint[i].X1 + "F2:" + lstPoint[i].X2 + "ClsJcPimDll.fnSetTxFreqs返回" + iRes, MSG_TYPE.ERROR_NET);
                        return false;
                    }
                    //ClsJcPimDll.fnSetTxOn(true, ClsJcPimDll.JC_CARRIER_TX1TX2);
                }
                evt_show_msg("exec: Set f1 = " + lstPoint[i].X1.ToString() + " ,f2 = " +
                                                 lstPoint[i].X2.ToString() + lf, MSG_TYPE.LOG_TEST);
                ClsJcPimDll.fnGetImResult(ref freq_mhz, ref val, "mhz");
                val += m_pim_settings.Offset_RX;
                JcPIMDataResults entry = new JcPIMDataResults();
                entry.No = i + 1;
                entry.F1 = (float)lstPoint[i].X1;
                entry.F2 = (float)lstPoint[i].X2;
                entry.Im_F = (float)freq_mhz;
                entry.Im_V = (float)val;
                entry.P1 = (float)Math.Round(p1, 1);
                entry.P2 = (float)Math.Round(p2, 1);
                entry.n1 = (int)n1;
                entry.n2 = (int)n2;
                m_pim_resultLists.Add(entry);
                evt_update_ui(entry, null);
            }

            ClsJcPimDll.fnSetTxOn(false, ClsJcPimDll.JC_CARRIER_TX1TX2);
            return true;
        }

        bool time_sweep()
        {
            Monitor.Enter(m_ctrl);
            m_ctrl.bQuit = false;
            Monitor.Exit(m_ctrl);
            int s;
            double freq_mhz = 0;
            double val = 0;
            s = ClsJcPimDll.HwSetMeasBand(m_pim_settings.Band_TX1,
                              m_pim_settings.Band_TX2,
                              m_pim_settings.Band_RX);
            s = ClsJcPimDll.HwSetDutPort(m_pim_settings.Port_TX1,
                                         m_pim_settings.Port_TX2,
                                         m_pim_settings.Port_RX);
            if (s <= -10000)
            {
                evt_show_msg("exec-Error: set switch error" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }
            ClsJcPimDll.fnSetImOrder((byte)m_pim_settings.Order);
            ClsJcPimDll.fnSetTxPower(m_pim_settings.TX1,
                         m_pim_settings.TX2,
                         m_pim_settings.Offset1,
                         m_pim_settings.Offset2);
            s = ClsJcPimDll.fnSetTxFreqs(m_pim_settings.F1s,
                             m_pim_settings.F2e,
                             "mhz");
            if (s == -10018)
            {
                evt_show_msg("exec-Error: No find power" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }
            else if (s <= -10000)
            {
                evt_show_msg("exec-Error: Tx out of range" + lf, MSG_TYPE.ERROR_NET);
                return false;
            }
            evt_show_msg("exec: Set f1 = " + m_pim_settings.F1s.ToString() + " ,f2 = " +
                                             m_pim_settings.F2e.ToString() + lf, MSG_TYPE.LOG_TEST);

            int i = 0;
            long time_start = DateTime.Now.Ticks;
            ClsJcPimDll.fnSetTxOn(true, ClsJcPimDll.JC_CARRIER_TX1TX2);

            while (true)
            {
                Monitor.Enter(m_ctrl);
                bool isQuit = m_ctrl.bQuit;
                Monitor.Exit(m_ctrl);
                if (isQuit)
                {
                    ClsJcPimDll.fnSetTxOn(false, ClsJcPimDll.JC_CARRIER_TX1TX2);
                    evt_show_msg("exec: test stop" + lf, MSG_TYPE.LOG_TEST);
                    return true;
                }

                TimeSpan elapsedSpan = new TimeSpan(DateTime.Now.Ticks - time_start);
                m_pim_settings.Time = m_pim_settings.Time == 0 ? 10 : m_pim_settings.Time;
                if (elapsedSpan.TotalSeconds >= m_pim_settings.Time)
                {
                    break;
                }

                ClsJcPimDll.fnGetImResult(ref freq_mhz, ref val, "mhz");
                val += m_pim_settings.Offset_RX;
                JcPIMDataResults entry = new JcPIMDataResults();
                entry.No = i;
                entry.F1 = (float)m_pim_settings.F1s;
                entry.F2 = (float)m_pim_settings.F2e;
                entry.Im_F = (float)freq_mhz;
                entry.Im_V = (float)val;
                entry.P1 = (float)m_pim_settings.TX1;
                entry.P2 = (float)m_pim_settings.TX2;
                entry.n1 = 0;
                entry.n2 = 0;
                m_pim_resultLists.Add(entry);
                evt_update_ui(entry, null);
                i++;
            }

            ClsJcPimDll.fnSetTxOn(false, ClsJcPimDll.JC_CARRIER_TX1TX2);
            return true;
        }
    }
}
